package com.objectdraw.server;

import java.net.Socket;
import java.util.Date;

import com.objectdraw.server.data.ResponseData;

/**
 * The sole purpose of this class is to monitor the object draw server. It will
 * cause timed actions to happen based on the status of the server.
 * 
 * @author Harrison
 */
public class ObjectDrawServerMonitor implements Runnable {

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Runnable#run()
	 */
	public void run() {
		ObjectDrawServer server = ObjectDrawServer.getInstance();
		while (true) {
			System.out.println("Running Observer");
			//Case1:idle drawer
			checkForIdleDrawer(server);
			
			//Case2: No current drawer defined.
			checkForNoDrawer(server);
			
			//Case3: Drawer held canvas too long
			checkForTimeLimit(server);

			try {
				// Wait 10 seconds before doing it again
				Thread.sleep(10000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * Checks to see if the canvas has been controlled by the current drawer longer
	 * than the acceptable time. If so,and there is someone waiting for control
	 * his control is released and it is passed to the next client in line.
	 * @param server
	 */
	private void checkForTimeLimit(ObjectDrawServer server) {
		String cur = server.getCurrentDrawer();
		
		//Is someone currently in control of the canvas?
		if(!"".equalsIgnoreCase(cur)){
			//Check time stamps
			long eps = server.getTimeLimit();
			Date start = server.getCurrentDrawerStartDate();
			long diff = (new Date().getTime()) - start.getTime();
			
			//Figure out if someone's waiting
			String next = server.getNextUserQueued();
			boolean waiting = ((null== next) || "".equalsIgnoreCase(next))?false:true;
			
			//Have we passed the time limit and is there someone waiting?
			if(diff >= eps && waiting){
				System.out.println("Server: Forcefully taking control from " +cur);
				ResponseData response = new ResponseData();
				response.addResponse("Control canvas ended" );
				
				Socket client = server.getCurrentDrawerConnection();
				CommunicationServer.broadcast(response, client);
				server.releaseControl();
				
				/** Give Control to the next person waiting **/
				
				System.out.println("Server: Control Assigned to " + next);
				
				//Give control to the next user
				server.setCurrentDrawer(next);		
				
				//Let the client know he now has control
				client = server.getCurrentDrawerConnection();
				response.addResponse("Control canvas");
				CommunicationServer.broadcast(response, client);
			}
			//Have we passed the time limit but no one is waiting?
			else if(diff >= eps && !waiting){
				System.out.println("Server: Time Limit Passed but no one is in queue");
			}
			//Leave this person in control until someone requests control
			else{
				
			}
		}
		else{
			//No one is in control so there's nothing to do			
		}
	}

	/**
	 * Checks to see if someone is in control of the canvas.  If no one is then it 
	 * must go through the process of assigning it to someone if anyone has asked
	 * @param server
	 */
	private void checkForNoDrawer(ObjectDrawServer server) {
		String cur = server.getCurrentDrawer();
		if("".equalsIgnoreCase(cur)){
			System.out.println("Server: Attempting to assign new drawer");
			String next = server.getNextUserQueued();
			
			if(!"".equalsIgnoreCase(next)){
				ResponseData response = new ResponseData();
				Socket client;
				System.out.println("Server: Control Assigned to " + next);

				//Give control to the next user
				server.setCurrentDrawer(next);		
				
				//Let the client know he now has control
				client = server.getCurrentDrawerConnection();
				response.addResponse("Control canvas");
				CommunicationServer.broadcast(response, client);
			}else{
				//Do Nothing
			}
		}
	}

	/**
	 * Determines if the current drawer has been idle for x time. If he has been
	 * idle then we release control from him and assign it to the next available
	 * person.
	 * 
	 * @param server
	 */
	private void checkForIdleDrawer(ObjectDrawServer server) {
		Date then = server.getCurrentDrawerLastActivityDate();
		if (then != null) { //There is a current drawer
			long eps = server.getIdleTimeLimit();
			long res = System.currentTimeMillis() - then.getTime();
			if (res >= eps) {
				System.out.println("Server: Idle Client connection detected");
				System.out.println("Server: Removing "+ server.getCurrentDrawer());

				// Get a connection to the client
				Socket client = server.getCurrentDrawerConnection();

				if (client != null && !client.isClosed()) {
						// Notify client he's losing control
						ResponseData response = new ResponseData();
						response.addResponse("Control canvas denied");
						CommunicationServer.broadcast(response, client);
				} else { // connection is dead; remove it
					server.removeClient(server.getCurrentDrawer());
				}

				// Remove control of the canvas from this client
				server.releaseControl();

				// Assign control to the next person in line
				String next = server.getNextUserQueued();
				if(!"".equals(next)){
					client = server.getDrawerConnection(next);
					if(client != null && !client.isClosed() && client.isConnected()){
						System.out.println("Server: Control assigned to " + next);
						server.setCurrentDrawer(next);
						ResponseData response = new ResponseData();
						response = new ResponseData();
						response.addResponse("Control canvas");
						CommunicationServer.broadcast(response, client);
					}else{
						//We lost our connection to the client so lets remove him from the cache
						server.removeClient(next);
						System.out.println("poop");
					}
				}else{
					//DO Nothing!
					//Wait for next round of processing and let no drawer handle it
				}
			}
		}
	}

}
